package com.it.schoolbookshop_back.interceptors;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.it.schoolbookshop_back.entities.po.User;
import com.it.schoolbookshop_back.service.UserService;
import com.it.schoolbookshop_back.utils.JwtUtil;
import com.it.schoolbookshop_back.utils.UserContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * JWT拦截器
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(JwtInterceptor.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    // 放行的路径
    private static final List<String> SKIP_AUTH_URLS = new ArrayList<>();
    static {
        SKIP_AUTH_URLS.add("/api/login");
        SKIP_AUTH_URLS.add("/api/register");
        SKIP_AUTH_URLS.add("/api/user/login");
        SKIP_AUTH_URLS.add("/api/user/register");
        SKIP_AUTH_URLS.add("/api/user/book");
        // 其他不需要验证的路径
    }

    @Autowired
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 对于OPTIONS请求直接放行
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            return true;
        }
        
        System.out.println("========= JWT拦截器被调用了！ =========");
        logger.info("========= JWT拦截器被调用了！ =========");
        
        // 记录请求开始时间
        LocalDateTime requestTime = LocalDateTime.now();
        
        // 收集请求信息
        Map<String, Object> requestInfo = new HashMap<>();
        requestInfo.put("timestamp", requestTime.format(formatter));
        requestInfo.put("method", request.getMethod());
        requestInfo.put("path", request.getRequestURI());
        requestInfo.put("query", request.getQueryString());
        requestInfo.put("contentType", request.getContentType());
        requestInfo.put("remoteAddr", request.getRemoteAddr());
        
        // 收集请求头信息
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        requestInfo.put("headers", headers);
        
        // 收集请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        requestInfo.put("parameters", parameterMap);
        
        // 从请求头中获取token
        String token = request.getHeader("Authorization");
        requestInfo.put("hasToken", token != null && token.startsWith("Bearer "));
        
        // 记录请求信息
        System.out.println("收到请求: " + objectMapper.writeValueAsString(requestInfo));
        logger.info("收到请求: {}", objectMapper.writeValueAsString(requestInfo));
        
        // 检查是否是需要跳过验证的URL
        String requestURI = request.getRequestURI();
        for (String skipUrl : SKIP_AUTH_URLS) {
            if (requestURI.equals(skipUrl) || 
                (skipUrl.endsWith("/**") && requestURI.startsWith(skipUrl.substring(0, skipUrl.length() - 3)))) {
                System.out.println("跳过验证的URL: " + requestURI);
                logger.info("跳过验证的URL: {}", requestURI);
                return true;
            }
        }
        
        // 如果请求头中没有token，返回未授权错误
        if (token == null || !token.startsWith("Bearer ")) {
            System.out.println("请求未携带有效token");
            logger.warn("请求未携带有效token");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        
        // 去掉Bearer前缀
        token = token.substring(7);
        
        try {
            // 验证并解析token
            DecodedJWT jwt = JwtUtil.parseToken(token);
            if (jwt == null) {
                System.out.println("token解析失败");
                logger.warn("token解析失败");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
            
            // 记录token信息
            Map<String, Object> tokenInfo = new HashMap<>();
            tokenInfo.put("userId", jwt.getClaim("userId").asString());
            tokenInfo.put("username", jwt.getClaim("username").asString());
            tokenInfo.put("issuedAt", jwt.getIssuedAt());
            tokenInfo.put("expiresAt", jwt.getExpiresAt());
            tokenInfo.put("issuer", jwt.getIssuer());
            System.out.println("Token信息: " + objectMapper.writeValueAsString(tokenInfo));
            logger.info("Token信息: {}", objectMapper.writeValueAsString(tokenInfo));
            
            // 检查token是否过期
            if (JwtUtil.isTokenExpired(token)) {
                System.out.println("token已过期");
                logger.warn("token已过期");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
            
            // 从token中获取用户ID
            String userId = jwt.getClaim("userId").asString();
            if (userId == null) {
                System.out.println("token中未包含用户ID");
                logger.warn("token中未包含用户ID");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
            
            // 从token中获取用户角色
            String role = jwt.getClaim("role").asString();
            
            // 查询用户信息
            User user = userService.getUserById(Integer.parseInt(userId));
            if (user == null) {
                System.out.println("未找到用户信息: " + userId);
                logger.warn("未找到用户信息: {}", userId);
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
            
            // 获取token中的username，如果为null则使用数据库中的用户名
            String username = jwt.getClaim("username").asString();
            if (username == null) {
                System.out.println("Token中username为null，使用数据库中的用户名: " + user.getUsername());
                logger.warn("Token中username为null，使用数据库中的用户名: {}", user.getUsername());
                username = user.getUsername();
            }
            
            // 将用户信息存入ThreadLocal
            UserContext.setUser(
                user.getId(),
                user.getUsername(),
                role != null ? role : user.getRole(),  // 优先使用token中的角色，否则使用数据库中的角色
                user.getRealName()
            );
            
            System.out.println("用户 [" + user.getUsername() + "] 请求验证通过");
            logger.info("用户 [{}] 请求验证通过", user.getUsername());
            
            // 记录请求处理时间
            System.out.println("请求处理耗时: " + (System.currentTimeMillis() - requestTime.atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli()) + "ms");
            logger.info("请求处理耗时: {}ms", System.currentTimeMillis() - requestTime.atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli());
            
            return true;
        } catch (Exception e) {
            System.out.println("请求处理异常: " + e.getMessage());
            logger.error("请求处理异常", e);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 确保请求结束时清除ThreadLocal中的用户信息
        UserContext.clear();
        System.out.println("========= 请求处理完成，ThreadLocal已清理 =========");
        logger.info("========= 请求处理完成，ThreadLocal已清理 =========");
    }
} 